#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <mysql/mysql.h>
#include <ctype.h>

#include "../inc/tcp.h"
#include "../inc/login.h"
#include "../inc/cJSON.h"

// 处理登录指令
void handle_login_cmd(client_info_p client, cJSON *root, cJSON *response)
{
    const char *userid = cJSON_GetStringValue(cJSON_GetObjectItem(root, "userid"));
    const char *password = cJSON_GetStringValue(cJSON_GetObjectItem(root, "password"));

    // 检查账号密码是否为空
    if (userid == NULL || password == NULL || *userid == '\0' || *password == '\0')
    {
        cJSON_AddNumberToObject(response, "code", LOGIN_ERROR_EMPTY_INPUT);
        cJSON_AddStringToObject(response, "message", "账号和密码不能为空");
        return;
    }

    int result = user_login(client, userid, password, client->connfd);
    const char *message = "";

    switch (result)
    {
    case LOGIN_SUCCESS:
        message = "登录成功!";
        break;
    case LOGIN_ERROR_USER_NOT_EXIST:
        message = "用户名不存在";
        break;
    case LOGIN_ERROR_PASSWORD:
        message = "密码错误";
        break;
    case LOGIN_ERROR_DB:
        message = "数据库错误";
        break;
    case LOGIN_ERROR_EMPTY_INPUT:
        message = "账号和密码不能为空";
        break;
    default:
        message = "未定义的错误码";
        break;
    }

    cJSON_AddNumberToObject(response, "code", result);
    cJSON_AddStringToObject(response, "message", message);
}

/**
 * 登录功能：检查旧连接并替换数据库中的connfd
 * @return 0=成功, 1=用户名不存在, 2=密码错误, 3=数据库错误
 */
int user_login(client_info_p client, const char *userid, const char *password, int new_connfd)
{
    char sql[512] = {0};
    MYSQL_RES *result = NULL;
    MYSQL_ROW row;
    int old_connfd = -1; // 存储旧连接的套接字

    if (mysql_check_and_reconnect(&client->db_conn) != 0)
    {
        return 3; // 重连失败，返回数据库错误
    }

    // 1. 验证用户名和密码
    snprintf(sql, sizeof(sql),
             "SELECT passwd FROM user WHERE userid = '%s' LIMIT 1", userid);
    if (mysql_query(client->db_conn, sql) != 0)
    {
        printf("[LOGIN] 查询密码失败: %s\n", mysql_error(client->db_conn));
        return 3;
    }

    result = mysql_store_result(client->db_conn);
    if (!result)
    {
        printf("[LOGIN] 获取密码结果失败: %s\n", mysql_error(client->db_conn));
        return 3;
    }

    // 用户名不存在
    if (mysql_num_rows(result) == 0)
    {
        mysql_free_result(result);
        return 1;
    }

    // 验证密码
    row = mysql_fetch_row(result);
    if (strcmp(row[0], password) != 0)
    {
        mysql_free_result(result);
        return 2;
    }
    mysql_free_result(result);

    // 检查用户是否已登录（查询旧连接）
    snprintf(sql, sizeof(sql),
             "SELECT connfd FROM online_user WHERE userid = '%s' LIMIT 1", userid);
    if (mysql_query(client->db_conn, sql) != 0)
    {
        printf("[LOGIN] 检查登录状态失败: %s\n", mysql_error(client->db_conn));
        return 3;
    }

    result = mysql_store_result(client->db_conn);
    if (!result)
    {
        printf("[LOGIN] 获取登录状态结果失败: %s\n", mysql_error(client->db_conn));
        return 3;
    }

    // 存在旧连接记录
    if (mysql_num_rows(result) > 0)
    {
        row = mysql_fetch_row(result);
        if (row[0] != NULL)
        {
            old_connfd = atoi(row[0]);
            if (old_connfd != -1)
            {
                if (old_connfd != -1)
                {
                    // 检查旧连接是否仍然有效
                    int error = 0;
                    socklen_t len = sizeof(error);

                    if (getsockopt(old_connfd, SOL_SOCKET, SO_ERROR, &error, &len) == 0 && error == 0)
                    {
                        // 连接仍然有效，强制下线
                        printf("[LOGIN] 用户 %s 已在其他端登录，强制下线 fd: %d\n", userid, old_connfd);
                        cJSON *root = cJSON_CreateObject();
                        cJSON_AddStringToObject(root, "type", "login");
                        cJSON_AddNumberToObject(root, "code", LOGIN_ERROR_ALREADY_LOGGED);
                        cJSON_AddStringToObject(root, "message", "您的账号在其他设备登录，已被强制下线");

                        // 转换为字符串并发送
                        char *json_str = cJSON_PrintUnformatted(root);
                        if (json_str != NULL)
                        {
                            send(old_connfd, json_str, strlen(json_str), 0);
                            free(json_str); // 释放JSON字符串内存
                        }

                        // 释放cJSON对象
                        cJSON_Delete(root);
                        close(old_connfd);
                    }
                    else
                    {
                        // 连接已无效，直接清理
                        printf("[LOGIN] 用户 %s 的旧连接 %d 已无效，直接清理\n", userid, old_connfd);
                        close(old_connfd); // 确保关闭
                    }
                }
            }
        }
    }
    mysql_free_result(result);

    // 替换数据库中的connfd 新增或更新记录
    snprintf(sql, sizeof(sql),
             "INSERT INTO online_user (userid, connfd, updated_at) "
             "VALUES ('%s', %d, CURRENT_TIMESTAMP) " // 插入新记录
             "ON DUPLICATE KEY UPDATE "              // 若userid已存在（唯一键冲突）
             "connfd = %d, "                         // 更新为新的connfd
             "updated_at = CURRENT_TIMESTAMP",       // 更新在线时间为当前时间
             userid, new_connfd, new_connfd);

    if (mysql_query(client->db_conn, sql) != 0)
    {
        printf("[LOGIN] 更新连接信息失败: %s\n", mysql_error(client->db_conn));
        return 3;
    }

    strcpy(client->userid, userid);
    printf("[LOGIN] 用户 %s 登录成功，新连接 fd: %d\n", userid, new_connfd);
    return 0;
}

/**
 * 退出登录：更新用户在线状态为0
 */
void user_logout(MYSQL *db_conn, const char *userid)
{
    if (strlen(userid) == 0)
        return; // 未登录用户无需处理
    char sql[512] = {0};
    snprintf(sql, sizeof(sql),
             "DELETE FROM online_user WHERE userid = '%s'",
             userid);
    if (mysql_query(db_conn, sql) != 0)
    {
        printf("[LOGOUT] 更新失败: %s\n", mysql_error(db_conn));
    }
    else
    {
        printf("[LOGOUT] 用户%s已离线\n", userid);
    }
}

/**
 * 获取用户在线的文件描述符
 * @return, >=0=文件描述符
 */
int get_user_online_fd(client_info_p client, const char *userid)
{
    if (!client->db_conn || !userid || !strlen(userid))
    {
        return -2;
    }

    char sql[512] = {0};
    MYSQL_RES *result = NULL;
    MYSQL_ROW row;
    int online_fd = -1; // 默认不在线

    snprintf(sql, sizeof(sql), "SELECT connfd FROM online_user WHERE userid = '%s' LIMIT 1", userid);
    if (mysql_query(client->db_conn, sql) != 0)
    {
        goto cleanup; // 数据库执行失败
    }

    // 获取结果集
    result = mysql_store_result(client->db_conn);
    if (!result)
    {
        goto cleanup;
    }

    // 提取有效fd
    if (mysql_num_rows(result) > 0 && (row = mysql_fetch_row(result)) && row[0] && strlen(row[0]))
    {
        online_fd = atoi(row[0]);
        online_fd = (online_fd > 0) ? online_fd : -1;
    }

// 资源清理
cleanup:
    if (result)
    {
        mysql_free_result(result);
    }

    return online_fd;
}

// 处理退出登录指令
void handle_log_out_cmd(client_info_p client, cJSON *root, cJSON *response)
{
    // 解析请求中的userid字段
    cJSON *userid_item = cJSON_GetObjectItem(root, "userid");
    const char *userid = NULL;
    if (userid_item != NULL && cJSON_IsString(userid_item))
    {
        userid = userid_item->valuestring;
    }

    //  检查参数合法性
    if (userid == NULL || strlen(userid) == 0)
    {
        cJSON_AddNumberToObject(response, "code", LOGOUT_STATUS_ERROR_EMPTY_USERID);
        cJSON_AddStringToObject(response, "message", "退出登录数据异常");
        return;
    }

    //  检查数据库连接（复用已有的重连逻辑，确保操作有效）
    if (mysql_check_and_reconnect(&client->db_conn) != 0)
    {
        cJSON_AddNumberToObject(response, "code", LOGOUT_STATUS_ERROR_DB);
        cJSON_AddStringToObject(response, "message", "数据库连接异常");
        return;
    }

    // // 关闭当前客户端连接
    // if (client->connfd > 0)
    // {
    //     close(client->connfd);
    //     client->connfd = -1; // 标记连接已关闭，避免重复操作
    //     printf("[LOGOUT] 已关闭用户 %s 的客户端连接 fd: %d\n", userid, client->connfd);
    // }

    //  调用已有函数清理在线记录
    user_logout(client->db_conn, userid);
    memset(client->userid, 0, sizeof(client->userid));

    // 填充成功响应
    cJSON_AddNumberToObject(response, "code", LOGOUT_STATUS_SUCCESS);
    cJSON_AddStringToObject(response, "message", "退出登录成功");
}
